﻿/*
时   间:  2015.8.18
作   者:  张存
邮   箱:  zhangcunliang@126.com
描   述:
    
修改记录: 
    2020.2.22  去掉oracle的引用，不使用oracle数据库时可以不需要 Oracle.ManagedDataAccess.dll
 
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.Common;
//using Oracle.ManagedDataAccess.Client;

namespace ASmile.ORM.Entitys
{
    /// <summary>
    /// 存储过程实体基类
    /// </summary>
    public class ProcEntityBase
    {
        /// <summary>
        /// 存储过程名称，如果为空则为类名称
        /// </summary>
        protected virtual string ProcedureName { get; set; }
        /// <summary>
        /// 获取存储过程名称
        /// </summary>
        public string GetProcedureName()
        {
            if (string.IsNullOrWhiteSpace(ProcedureName))
            {
                string className = this.GetType().Name;
                string fistStr = "";
                ProcedureName = className.Substring(fistStr.Length, className.Length - fistStr.Length);
            }
            return ProcedureName;
        }
        /// <summary>
        /// 设置过程名 (不用属性，反射为过滤)
        /// </summary>
        public void SetProcedureName(string procName)
        {
            ProcedureName = procName;
        }

        /// <summary>
        /// 输出参数的属性字典,key包含@
        /// </summary>
        readonly List<OutParam> _OutParamList = new List<OutParam>();

        class OutParam
        {
            public string PropertyName { set; get; }

            public string ParameterName { set; get; }
        }

        /// <summary>
        /// 获得存储过程参数集合
        /// </summary>
        protected internal virtual DbParameter[] GetProcParamObj(
            Func<string, object, DbParameter> CreateProArgHandle,
            Dictionary<string, object> otherArgs = null)
        {
            var procParam = new List<DbParameter>();
            Type t = this.GetType();
            System.Reflection.PropertyInfo[] pros = t.GetProperties();
            _OutParamList.Clear();
            foreach (System.Reflection.PropertyInfo item in pros)
            {
                Attribute attr = ProcParamAttribute.GetCustomAttribute(item, typeof(ProcParamAttribute));
                ProcParamAttribute paramAttr = attr as ProcParamAttribute;
                if (paramAttr == null)
                {
                    paramAttr = new ProcParamAttribute();
                }
                else
                {
                    if (paramAttr.NotParameter) continue;
                }
                if (string.IsNullOrWhiteSpace(paramAttr.ParameterName))
                {
                    paramAttr.ParameterName = item.Name;
                }
                object paramValue = item.GetValue(this, null);
                if (paramValue == null) paramValue = DBNull.Value;
                DbParameter param = CreateProArgHandle(paramAttr.ParameterName, paramValue);

                param.Direction = paramAttr.ParamDirection;
                if (paramAttr.IsOracleCursor)
                {
                    this.SetOracleCursor(param);
                    //oracle 返回datatable必须指定一个游标类型的参数用来输出
                    //Type oracleParamType = param.GetType();
                    //var oclDbType = oracleParamType.GetProperty("OracleDbType");
                    //oclDbType.SetValue(param, Oracle.ManagedDataAccess.Client.OracleDbType.RefCursor, null);                    
                }
                if (paramAttr.ParamDirection == ParameterDirection.InputOutput || paramAttr.ParamDirection == ParameterDirection.Output)
                {
                    //如果其它
                    param.Size = paramAttr.OutSize;
                    _OutParamList.Add(new OutParam() { ParameterName = param.ParameterName, PropertyName = item.Name });
                }
                procParam.Add(param);
            }
            if (otherArgs != null)
            {
                foreach (var item in otherArgs)
                {
                    //如果参数已存在，取other参数值
                    var old = procParam.Find(s => s.ParameterName == item.Key);
                    if (old != null)
                    {
                        old.Value = item.Value;
                    }
                    else
                    {
                        DbParameter param = CreateProArgHandle(item.Key, item.Value);
                        procParam.Add(param);
                    }
                }
            }
            return procParam.ToArray();
        }
        /// <summary>
        /// 给当前对象设置输出参数的值
        /// </summary>
        protected internal virtual void SetOutParamValue(DbParameter[] dbParams)
        {
            if (dbParams == null || dbParams.Length == 0) return;
            Type t = this.GetType();
            object pValue;
            foreach (var item in _OutParamList)
            {
                System.Reflection.PropertyInfo pro = t.GetProperty(item.PropertyName);
                var param = dbParams.First(s => s.ParameterName == item.ParameterName);
                if (param != null && param.Value != DBNull.Value)
                {
                    if (this.GetType() != pro.PropertyType)
                    {
                        var targetType = Nullable.GetUnderlyingType(pro.PropertyType);
                        if (targetType == null)
                        {
                            targetType = pro.PropertyType;
                        }
                        if (targetType.Name.Equals("Guid", StringComparison.CurrentCultureIgnoreCase))
                        {
                            pValue = new Guid(param.Value.ToString());
                        }
                        else
                        {
                            pValue = Convert.ChangeType(param.Value.ToString(), targetType);
                        }
                    }
                    else
                    {
                        pValue = param.Value;
                    }

                    pro.SetValue(this, pValue, null);
                }
            }
        }
    }
}